
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
  <head>
    <meta charset="utf-8" />
    <title>pickle —— Python 对象序列化 &#8212; Python 3.7.8 文档</title>
    <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <script type="text/javascript" src="../_static/translations.js"></script>
    
    <script type="text/javascript" src="../_static/sidebar.js"></script>
    
    <link rel="search" type="application/opensearchdescription+xml"
          title="在 Python 3.7.8 文档 中搜索"
          href="../_static/opensearch.xml"/>
    <link rel="author" title="关于这些文档" href="../about.html" />
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="copyright" title="版权所有" href="../copyright.html" />
    <link rel="next" title="copyreg --- 注意 pickle 支持函数" href="copyreg.html" />
    <link rel="prev" title="数据持久化" href="persistence.html" />
    <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
    <link rel="canonical" href="https://docs.python.org/3/library/pickle.html" />
    
    <script type="text/javascript" src="../_static/copybutton.js"></script>
    
    
    
    
    <style>
      @media only screen {
        table.full-width-table {
            width: 100%;
        }
      }
    </style>
 

  </head><body>
  
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>导航</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="总目录"
             accesskey="I">索引</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python 模块索引"
             >模块</a> |</li>
        <li class="right" >
          <a href="copyreg.html" title="copyreg --- 注意 pickle 支持函数"
             accesskey="N">下一页</a> |</li>
        <li class="right" >
          <a href="persistence.html" title="数据持久化"
             accesskey="P">上一页</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="https://www.python.org/">Python</a> &#187;</li>
        <li>
          <a href="../index.html">3.7.8 Documentation</a> &#187;
        </li>

          <li class="nav-item nav-item-1"><a href="index.html" >Python 标准库</a> &#187;</li>
          <li class="nav-item nav-item-2"><a href="persistence.html" accesskey="U">数据持久化</a> &#187;</li>
    <li class="right">
        

    <div class="inline-search" style="display: none" role="search">
        <form class="inline-search" action="../search.html" method="get">
          <input placeholder="快速搜索" type="text" name="q" />
          <input type="submit" value="转向" />
          <input type="hidden" name="check_keywords" value="yes" />
          <input type="hidden" name="area" value="default" />
        </form>
    </div>
    <script type="text/javascript">$('.inline-search').show(0);</script>
         |
    </li>

      </ul>
    </div>    

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <div class="section" id="module-pickle">
<span id="pickle-python-object-serialization"></span><h1><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> —— Python 对象序列化<a class="headerlink" href="#module-pickle" title="永久链接至标题">¶</a></h1>
<p><strong>源代码：</strong> <a class="reference external" href="https://github.com/python/cpython/tree/3.7/Lib/pickle.py">Lib/pickle.py</a></p>
<hr class="docutils" id="index-0" />
<p>模块 <a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 实现了对一个 Python 对象结构的二进制序列化和反序列化。 <em>&quot;Pickling&quot;</em> 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程，而 <em>&quot;unpickling&quot;</em> 是相反的操作，会将（来自一个 <a class="reference internal" href="../glossary.html#term-binary-file"><span class="xref std std-term">binary file</span></a> 或者 <a class="reference internal" href="../glossary.html#term-bytes-like-object"><span class="xref std std-term">bytes-like object</span></a> 的）字节流转化回一个对象层次结构。Pickling（和 unpickling）也被称为“序列化”, “编组” <a class="footnote-reference brackets" href="#id6" id="id1">1</a> 或者 “平面化”。而为了避免混乱，此处采用术语 “pickling” 和 “unpickling”。</p>
<div class="admonition warning">
<p class="admonition-title">警告</p>
<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块在接受被错误地构造或者被恶意地构造的数据时不安全。永远不要 unpickle 来自于不受信任的或者未经验证的来源的数据。</p>
</div>
<div class="section" id="relationship-to-other-python-modules">
<h2>与其他 Python 模块间的关系<a class="headerlink" href="#relationship-to-other-python-modules" title="永久链接至标题">¶</a></h2>
<div class="section" id="comparison-with-marshal">
<h3>与 <code class="docutils literal notranslate"><span class="pre">marshal</span></code> 间的关系<a class="headerlink" href="#comparison-with-marshal" title="永久链接至标题">¶</a></h3>
<p>Python 有一个更原始的序列化模块称为 <a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a>，但一般地 <a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 应该是序列化 Python 对象时的首选。<a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a> 存在主要是为了支持 Python 的 <code class="file docutils literal notranslate"><span class="pre">.pyc</span></code> 文件.</p>
<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块与 <a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a> 在如下几方面显著地不同：</p>
<ul>
<li><p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块会跟踪已被序列化的对象，所以该对象之后再次被引用时不会再次被序列化。<a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a> 不会这么做。</p>
<p>这隐含了递归对象和共享对象。递归对象指包含对自己的引用的对象。这种对象并不会被 marshal 接受，并且实际上尝试 marshal 递归对象会让你的 Python 解释器崩溃。对象共享发生在对象层级中存在多处引用同一对象时。<a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 只会存储这些对象一次，并确保其他的引用指向同一个主副本。共享对象将保持共享，这可能对可变对象非常重要。</p>
</li>
<li><p><a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a> 不能被用于序列化用户定义类及其实例。<a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 能够透明地存储并保存类实例，然而此时类定义必须能够从与被存储时相同的模块被引入。</p></li>
<li><p>同样用于序列化的 <a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a> 格式不保证数据能移植到不同的 Python 版本中。因为它的主要任务是支持 <code class="file docutils literal notranslate"><span class="pre">.pyc</span></code> 文件，必要时会以破坏向后兼容的方式更改这种序列化格式，为此 Python 的实现者保留了更改格式的权利。<a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 序列化格式可以在不同版本的 Python 中实现向后兼容，前提是选择了合适的 pickle 协议。如果你的数据要在 Python 2 与 Python 3 之间跨越传递，Pickling 和 Unpickling 的代码在 2 和 3 之间也是不同的。</p></li>
</ul>
</div>
<div class="section" id="comparison-with-json">
<h3>与 <code class="docutils literal notranslate"><span class="pre">json</span></code> 模块的比较<a class="headerlink" href="#comparison-with-json" title="永久链接至标题">¶</a></h3>
<p>Pickle 协议和 <a class="reference external" href="http://json.org">JSON (JavaScript Object Notation)</a> 间有着本质的不同：</p>
<ul class="simple">
<li><p>JSON 是一个文本序列化格式（它输出 unicode 文本，尽管在大多数时候它会接着以 <code class="docutils literal notranslate"><span class="pre">utf-8</span></code> 编码），而 pickle 是一个二进制序列化格式；</p></li>
<li><p>JSON 是我们可以直观阅读的，而 pickle 不是；</p></li>
<li><p>JSON是可互操作的，在Python系统之外广泛使用，而pickle则是Python专用的；</p></li>
<li><p>默认情况下，JSON 只能表示 Python 内置类型的子集，不能表示自定义的类；但 pickle 可以表示大量的 Python 数据类型（可以合理使用 Python 的对象内省功能自动地表示大多数类型，复杂情况可以通过实现 <a class="reference internal" href="#pickle-inst"><span class="std std-ref">specific object APIs</span></a> 来解决）。</p></li>
</ul>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<p><a class="reference internal" href="json.html#module-json" title="json: Encode and decode the JSON format."><code class="xref py py-mod docutils literal notranslate"><span class="pre">json</span></code></a> 模块:一个允许JSON序列化和反序列化的标准库模块</p>
</div>
</div>
</div>
<div class="section" id="data-stream-format">
<span id="pickle-protocols"></span><h2>数据流格式<a class="headerlink" href="#data-stream-format" title="永久链接至标题">¶</a></h2>
<p id="index-1"><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 所使用的数据格式仅可用于 Python。这样做的好处是没有外部标准给该格式强加限制，比如 JSON 或 XDR（不能表示共享指针）标准；但这也意味着非 Python 程序可能无法重新读取 pickle 打包的 Python 对象。</p>
<p>默认情况下，<a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 格式使用相对紧凑的二进制来存储。如果需要让文件更小，可以高效地 <a class="reference internal" href="archiving.html"><span class="doc">压缩</span></a> 由 pickle 打包的数据。</p>
<p><a class="reference internal" href="pickletools.html#module-pickletools" title="pickletools: Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickletools</span></code></a> 模块包含了相应的工具用于分析 <a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 生成的数据流。<a class="reference internal" href="pickletools.html#module-pickletools" title="pickletools: Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickletools</span></code></a> 源码中包含了对 pickle 协议使用的操作码的大量注释。</p>
<p>当前用于 pickling 的协议共有 5 种。使用的协议版本越高，读取生成的 pickle 所需的 Python 版本就要越新。</p>
<ul class="simple">
<li><p>v0 版协议是原始的“人类可读”协议，并且向后兼容早期版本的 Python。</p></li>
<li><p>v1 版协议是较早的二进制格式，它也与早期版本的 Python 兼容。</p></li>
<li><p>v2 版协议是在 Python 2.3 中引入的。它为存储 <a class="reference internal" href="../glossary.html#term-new-style-class"><span class="xref std std-term">new-style class</span></a> 提供了更高效的机制。欲了解有关第 2 版协议带来的改进，请参阅 <span class="target" id="index-10"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0307"><strong>PEP 307</strong></a>。</p></li>
<li><p>v3 版协议添加于 Python 3.0。它具有对 <a class="reference internal" href="stdtypes.html#bytes" title="bytes"><code class="xref py py-class docutils literal notranslate"><span class="pre">bytes</span></code></a> 对象的显式支持，且无法被 Python 2.x 打开。这是目前默认使用的协议，也是在要求与其他 Python 3 版本兼容时的推荐协议。</p></li>
<li><p>v4 版协议添加于 Python 3.4。它支持存储非常大的对象，能存储更多种类的对象，还包括一些针对数据格式的优化。有关第 4 版协议带来改进的信息，请参阅 <span class="target" id="index-11"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-3154"><strong>PEP 3154</strong></a>。</p></li>
</ul>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>序列化是一种比持久化更底层的概念，虽然 <a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 读取和写入的是文件对象，但它不处理持久对象的命名问题，也不处理对持久对象的并发访问（甚至更复杂）的问题。<a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块可以将复杂对象转换为字节流，也可以将字节流转换为具有相同内部结构的对象。处理这些字节流最常见的做法是将它们写入文件，但它们也可以通过网络发送或存储在数据库中。<a class="reference internal" href="shelve.html#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal notranslate"><span class="pre">shelve</span></code></a> 模块提供了一个简单的接口，用于在 DBM 类型的数据库文件上 pickle 和 unpickle 对象。</p>
</div>
</div>
<div class="section" id="module-interface">
<h2>模块接口<a class="headerlink" href="#module-interface" title="永久链接至标题">¶</a></h2>
<p>要序列化某个包含层次结构的对象，只需调用 <a class="reference internal" href="#pickle.dumps" title="pickle.dumps"><code class="xref py py-func docutils literal notranslate"><span class="pre">dumps()</span></code></a> 函数即可。同样，要反序列化数据流，可以调用 <a class="reference internal" href="#pickle.loads" title="pickle.loads"><code class="xref py py-func docutils literal notranslate"><span class="pre">loads()</span></code></a> 函数。但是，如果要对序列化和反序列化加以更多的控制，可以分别创建 <a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 或 <a class="reference internal" href="#pickle.Unpickler" title="pickle.Unpickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Unpickler</span></code></a> 对象。</p>
<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块包含了以下常量：</p>
<dl class="data">
<dt id="pickle.HIGHEST_PROTOCOL">
<code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">HIGHEST_PROTOCOL</code><a class="headerlink" href="#pickle.HIGHEST_PROTOCOL" title="永久链接至目标">¶</a></dt>
<dd><p>整数，可用的最高 <a class="reference internal" href="#pickle-protocols"><span class="std std-ref">协议版本</span></a>。此值可以作为 <em>协议</em> 值传递给 <a class="reference internal" href="#pickle.dump" title="pickle.dump"><code class="xref py py-func docutils literal notranslate"><span class="pre">dump()</span></code></a> 和 <a class="reference internal" href="#pickle.dumps" title="pickle.dumps"><code class="xref py py-func docutils literal notranslate"><span class="pre">dumps()</span></code></a> 函数，以及 <a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 的构造函数。</p>
</dd></dl>

<dl class="data">
<dt id="pickle.DEFAULT_PROTOCOL">
<code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">DEFAULT_PROTOCOL</code><a class="headerlink" href="#pickle.DEFAULT_PROTOCOL" title="永久链接至目标">¶</a></dt>
<dd><p>一个整数，表示封存操作使用的 <a class="reference internal" href="#pickle-protocols"><span class="std std-ref">协议版本</span></a>。 它可能小于 <a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。 当前默认协议版本为 3，它是一个为 Python 3 设计的新协议。</p>
</dd></dl>

<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块提供了以下方法，让打包过程更加方便。</p>
<dl class="function">
<dt id="pickle.dump">
<code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">dump</code><span class="sig-paren">(</span><em class="sig-param">obj</em>, <em class="sig-param">file</em>, <em class="sig-param">protocol=None</em>, <em class="sig-param">*</em>, <em class="sig-param">fix_imports=True</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.dump" title="永久链接至目标">¶</a></dt>
<dd><p>将打包好的对象 <em>obj</em> 写入已打开的 <a class="reference internal" href="../glossary.html#term-file-object"><span class="xref std std-term">file object</span></a> <em>file</em>。它等同于 <code class="docutils literal notranslate"><span class="pre">Pickler(file,</span> <span class="pre">protocol).dump(obj)</span></code>。</p>
<p>可选参数 <em>protocol</em> 是一个整数，告知 pickler 使用指定的协议，可选择的协议范围从 0 到 <a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。如果没有指定，这一参数默认值为 <a class="reference internal" href="#pickle.DEFAULT_PROTOCOL" title="pickle.DEFAULT_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">DEFAULT_PROTOCOL</span></code></a>。指定一个负数就相当于指定 <a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</p>
<p>参数 <em>file</em> 必须有一个 write() 方法，该 write() 方法要能接收字节作为其唯一参数。因此，它可以是一个打开的磁盘文件（用于写入二进制内容），也可以是一个 <a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal notranslate"><span class="pre">io.BytesIO</span></code></a> 实例，也可以是满足这一接口的其他任何自定义对象。</p>
<p>如果 <em>fix_imports</em> 为 True 且 <em>protocol</em> 小于 3，pickle 将尝试将 Python 3 中的新名称映射到 Python 2 中的旧模块名称，因此 Python 2 也可以读取打包出的数据流。</p>
</dd></dl>

<dl class="function">
<dt id="pickle.dumps">
<code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">dumps</code><span class="sig-paren">(</span><em class="sig-param">obj</em>, <em class="sig-param">protocol=None</em>, <em class="sig-param">*</em>, <em class="sig-param">fix_imports=True</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.dumps" title="永久链接至目标">¶</a></dt>
<dd><p>将 <em>obj</em> 打包以后的对象作为 <a class="reference internal" href="stdtypes.html#bytes" title="bytes"><code class="xref py py-class docutils literal notranslate"><span class="pre">bytes</span></code></a> 类型直接返回，而不是将其写入到文件。</p>
<p>参数 <em>protocol</em> 和 <em>fix_imports</em> 的含义与它们在 <a class="reference internal" href="#pickle.dump" title="pickle.dump"><code class="xref py py-func docutils literal notranslate"><span class="pre">dump()</span></code></a> 中的含义相同。</p>
</dd></dl>

<dl class="function">
<dt id="pickle.load">
<code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">load</code><span class="sig-paren">(</span><em class="sig-param">file</em>, <em class="sig-param">*</em>, <em class="sig-param">fix_imports=True</em>, <em class="sig-param">encoding=&quot;ASCII&quot;</em>, <em class="sig-param">errors=&quot;strict&quot;</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.load" title="永久链接至目标">¶</a></dt>
<dd><p>从已打开的 <a class="reference internal" href="../glossary.html#term-file-object"><span class="xref std std-term">file object</span></a> <em>文件</em> 中读取打包后的对象，重建其中特定对象的层次结构并返回。它相当于 <code class="docutils literal notranslate"><span class="pre">Unpickler(file).load()</span></code>。</p>
<p>Pickle 协议版本是自动检测出来的，所以不需要参数来指定协议。打包对象以外的其他字节将被忽略。</p>
<p>参数 <em>file</em> 必须有两个方法，其中 read() 方法接受一个整数参数，而 readline() 方法不需要参数。 两个方法都应返回字节串。 因此 <em>file</em> 可以是一个打开用于二进制读取的磁盘文件、一个 <a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal notranslate"><span class="pre">io.BytesIO</span></code></a> 对象，或者任何满足此接口要求的其他自定义对象。</p>
<p>可选的关键字参数是 <em>fix_imports</em>, <em>encoding</em> 和 <em>errors</em>，用于控制由Python 2 生成的 pickle 流的兼容性。如果 <em>fix_imports</em> 为 true，则 pickle 将尝试将旧的 Python 2 名称映射到 Python 3 中对应的新名称。<em>encoding</em> 和 <em>errors</em> 参数告诉 pickle 如何解码 Python 2 存储的 8 位字符串实例；这两个参数默认分别为 'ASCII' 和 'strict'。 <em>encoding</em> 参数可置为 'bytes' 来将这些 8 位字符串实例读取为字节对象。读取 NumPy array 和 Python 2 存储的 <a class="reference internal" href="datetime.html#datetime.datetime" title="datetime.datetime"><code class="xref py py-class docutils literal notranslate"><span class="pre">datetime</span></code></a>、<a class="reference internal" href="datetime.html#datetime.date" title="datetime.date"><code class="xref py py-class docutils literal notranslate"><span class="pre">date</span></code></a> 和 <a class="reference internal" href="datetime.html#datetime.time" title="datetime.time"><code class="xref py py-class docutils literal notranslate"><span class="pre">time</span></code></a> 实例时，请使用 <code class="docutils literal notranslate"><span class="pre">encoding='latin1'</span></code>。</p>
</dd></dl>

<dl class="function">
<dt id="pickle.loads">
<code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">loads</code><span class="sig-paren">(</span><em class="sig-param">data</em>, <em class="sig-param">*</em>, <em class="sig-param">fix_imports=True</em>, <em class="sig-param">encoding=&quot;ASCII&quot;</em>, <em class="sig-param">errors=&quot;strict&quot;</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.loads" title="永久链接至目标">¶</a></dt>
<dd><p>重建并返回一个对象的封存表示形式 <em>data</em> 的对象层级结构。 <em>data</em> 必须为 <a class="reference internal" href="../glossary.html#term-bytes-like-object"><span class="xref std std-term">bytes-like object</span></a>。</p>
<p>Pickle 协议版本是自动检测出来的，所以不需要参数来指定协议。打包对象以外的其他字节将被忽略。</p>
<p>可选的关键字参数是 <em>fix_imports</em>, <em>encoding</em> 和 <em>errors</em>，用于控制由Python 2 生成的 pickle 流的兼容性。如果 <em>fix_imports</em> 为 true，则 pickle 将尝试将旧的 Python 2 名称映射到 Python 3 中对应的新名称。<em>encoding</em> 和 <em>errors</em> 参数告诉 pickle 如何解码 Python 2 存储的 8 位字符串实例；这两个参数默认分别为 'ASCII' 和 'strict'。 <em>encoding</em> 参数可置为 'bytes' 来将这些 8 位字符串实例读取为字节对象。读取 NumPy array 和 Python 2 存储的 <a class="reference internal" href="datetime.html#datetime.datetime" title="datetime.datetime"><code class="xref py py-class docutils literal notranslate"><span class="pre">datetime</span></code></a>、<a class="reference internal" href="datetime.html#datetime.date" title="datetime.date"><code class="xref py py-class docutils literal notranslate"><span class="pre">date</span></code></a> 和 <a class="reference internal" href="datetime.html#datetime.time" title="datetime.time"><code class="xref py py-class docutils literal notranslate"><span class="pre">time</span></code></a> 实例时，请使用 <code class="docutils literal notranslate"><span class="pre">encoding='latin1'</span></code>。</p>
</dd></dl>

<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块定义了以下 3 个异常：</p>
<dl class="exception">
<dt id="pickle.PickleError">
<em class="property">exception </em><code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">PickleError</code><a class="headerlink" href="#pickle.PickleError" title="永久链接至目标">¶</a></dt>
<dd><p>其他 pickle 异常的基类。它是 <a class="reference internal" href="exceptions.html#Exception" title="Exception"><code class="xref py py-exc docutils literal notranslate"><span class="pre">Exception</span></code></a> 的一个子类。</p>
</dd></dl>

<dl class="exception">
<dt id="pickle.PicklingError">
<em class="property">exception </em><code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">PicklingError</code><a class="headerlink" href="#pickle.PicklingError" title="永久链接至目标">¶</a></dt>
<dd><p>当 <a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 遇到无法解包的对象时抛出此错误。它是 <a class="reference internal" href="#pickle.PickleError" title="pickle.PickleError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">PickleError</span></code></a> 的子类。</p>
<p>参考 <a class="reference internal" href="#pickle-picklable"><span class="std std-ref">可以被打包/解包的对象</span></a> 来了解哪些对象可以被打包。</p>
</dd></dl>

<dl class="exception">
<dt id="pickle.UnpicklingError">
<em class="property">exception </em><code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">UnpicklingError</code><a class="headerlink" href="#pickle.UnpicklingError" title="永久链接至目标">¶</a></dt>
<dd><p>当解包出错时抛出此异常，例如数据损坏或对象不安全。它是 <a class="reference internal" href="#pickle.PickleError" title="pickle.PickleError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">PickleError</span></code></a> 的子类。</p>
<p>注意，解包时可能还会抛出其他异常，包括（但不限于） AttributeError、EOFError、ImportError 和 IndexError。</p>
</dd></dl>

<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块可导出两个类，<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 和 <a class="reference internal" href="#pickle.Unpickler" title="pickle.Unpickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Unpickler</span></code></a>:</p>
<dl class="class">
<dt id="pickle.Pickler">
<em class="property">class </em><code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">Pickler</code><span class="sig-paren">(</span><em class="sig-param">file</em>, <em class="sig-param">protocol=None</em>, <em class="sig-param">*</em>, <em class="sig-param">fix_imports=True</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Pickler" title="永久链接至目标">¶</a></dt>
<dd><p>它接受一个二进制文件用于写入 pickle 数据流。</p>
<p>可选参数 <em>protocol</em> 是一个整数，告知 pickler 使用指定的协议，可选择的协议范围从 0 到 <a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。如果没有指定，这一参数默认值为 <a class="reference internal" href="#pickle.DEFAULT_PROTOCOL" title="pickle.DEFAULT_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">DEFAULT_PROTOCOL</span></code></a>。指定一个负数就相当于指定 <a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal notranslate"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</p>
<p>参数 <em>file</em> 必须有一个 write() 方法，该 write() 方法要能接收字节作为其唯一参数。因此，它可以是一个打开的磁盘文件（用于写入二进制内容），也可以是一个 <a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal notranslate"><span class="pre">io.BytesIO</span></code></a> 实例，也可以是满足这一接口的其他任何自定义对象。</p>
<p>如果 <em>fix_imports</em> 为 True 且 <em>protocol</em> 小于 3，pickle 将尝试将 Python 3 中的新名称映射到 Python 2 中的旧模块名称，因此 Python 2 也可以读取打包出的数据流。</p>
<dl class="method">
<dt id="pickle.Pickler.dump">
<code class="sig-name descname">dump</code><span class="sig-paren">(</span><em class="sig-param">obj</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Pickler.dump" title="永久链接至目标">¶</a></dt>
<dd><p>将 <em>obj</em> 打包后的内容写入已打开的文件对象，该文件对象已经在构造函数中指定。</p>
</dd></dl>

<dl class="method">
<dt id="pickle.Pickler.persistent_id">
<code class="sig-name descname">persistent_id</code><span class="sig-paren">(</span><em class="sig-param">obj</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Pickler.persistent_id" title="永久链接至目标">¶</a></dt>
<dd><p>默认什么也不做。它存在是为了让子类可以重载它。</p>
<p>如果 <a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_id()</span></code></a> 返回 <code class="docutils literal notranslate"><span class="pre">None</span></code>，<em>obj</em> 会被照常 pickle。如果返回其他值，<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 会将这个函数的返回值作为 <em>obj</em> 的持久化 ID（Pickler 本应得到序列化数据流并将其写入文件，若此函数有返回值，则得到此函数的返回值并写入文件）。这个持久化 ID 的解释应当定义在 <a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Unpickler.persistent_load()</span></code></a> 中（该方法定义还原对象的过程，并返回得到的对象）。注意，<a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_id()</span></code></a> 的返回值本身不能拥有持久化 ID。</p>
<p>参阅 <a class="reference internal" href="#pickle-persistent"><span class="std std-ref">持久化外部对象</span></a> 获取详情和使用示例。</p>
</dd></dl>

<dl class="attribute">
<dt id="pickle.Pickler.dispatch_table">
<code class="sig-name descname">dispatch_table</code><a class="headerlink" href="#pickle.Pickler.dispatch_table" title="永久链接至目标">¶</a></dt>
<dd><p>Pickler 对象的 dispatch 表是 <a class="reference internal" href="copyreg.html#copyreg.pickle" title="copyreg.pickle"><code class="xref py py-func docutils literal notranslate"><span class="pre">copyreg.pickle()</span></code></a> 中用到的 <em>reduction 函数</em> 的注册。dispatch 表本身是一个 class 到其 reduction 函数的映射键值对。一个 reduction 函数只接受一个参数，就是其关联的 class，函数行为应当遵守 <a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 接口规范。</p>
<p>Pickler 对象默认并没有 <a class="reference internal" href="#pickle.Pickler.dispatch_table" title="pickle.Pickler.dispatch_table"><code class="xref py py-attr docutils literal notranslate"><span class="pre">dispatch_table</span></code></a> 属性，该对象默认使用 <a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">copyreg</span></code></a> 模块中定义的全局 dispatch 表。如果要为特定 Pickler 对象自定义序列化过程，可以将 <a class="reference internal" href="#pickle.Pickler.dispatch_table" title="pickle.Pickler.dispatch_table"><code class="xref py py-attr docutils literal notranslate"><span class="pre">dispatch_table</span></code></a> 属性设置为类字典对象（dict-like object）。另外，如果 <a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 的子类设置了 <a class="reference internal" href="#pickle.Pickler.dispatch_table" title="pickle.Pickler.dispatch_table"><code class="xref py py-attr docutils literal notranslate"><span class="pre">dispatch_table</span></code></a> 属性，则该子类的实例会使用这个表作为默认的 dispatch 表。</p>
<p>参阅 <a class="reference internal" href="#pickle-dispatch"><span class="std std-ref">Dispatch 表</span></a> 获取使用示例。</p>
<div class="versionadded">
<p><span class="versionmodified added">3.3 新版功能.</span></p>
</div>
</dd></dl>

<dl class="attribute">
<dt id="pickle.Pickler.fast">
<code class="sig-name descname">fast</code><a class="headerlink" href="#pickle.Pickler.fast" title="永久链接至目标">¶</a></dt>
<dd><p>已弃用。设为 True 则启用快速模式。快速模式禁用了“备忘录” (memo) 的使用，即不生成多余的 PUT 操作码来加快打包过程。不应将其与自指 (self-referential) 对象一起使用，否则将导致 <a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Pickler</span></code></a> 无限递归。</p>
<p>如果需要进一步提高 pickle 的压缩率，请使用 <a class="reference internal" href="pickletools.html#pickletools.optimize" title="pickletools.optimize"><code class="xref py py-func docutils literal notranslate"><span class="pre">pickletools.optimize()</span></code></a>。</p>
</dd></dl>

</dd></dl>

<dl class="class">
<dt id="pickle.Unpickler">
<em class="property">class </em><code class="sig-prename descclassname">pickle.</code><code class="sig-name descname">Unpickler</code><span class="sig-paren">(</span><em class="sig-param">file</em>, <em class="sig-param">*</em>, <em class="sig-param">fix_imports=True</em>, <em class="sig-param">encoding=&quot;ASCII&quot;</em>, <em class="sig-param">errors=&quot;strict&quot;</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Unpickler" title="永久链接至目标">¶</a></dt>
<dd><p>它接受一个二进制文件用于读取 pickle 数据流。</p>
<p>Pickle 协议版本是自动检测出来的，所以不需要参数来指定协议。</p>
<p>参数 <em>file</em> 必须有两个方法，其中 read() 方法接受一个整数参数，而 readline() 方法不需要参数。 两个方法都应返回字节串。 因此 <em>file</em> 可以是一个打开用于二进制读取的磁盘文件对象、一个 <a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal notranslate"><span class="pre">io.BytesIO</span></code></a> 对象，或者任何满足此接口要求的其他自定义对象。</p>
<p>可选的关键字参数有 <em>fix_imports</em>, <em>encoding</em> 和 <em>errors</em>，它们用于控制由 Python 2 所生成 pickle 流的兼容性支持。 如果 <em>fix_imports</em> 为真值，则 pickle 将尝试把旧的 Python 2 名称映射到 Python 3 所使用的新名称。 <em>encoding</em> 和 <em>errors</em> 将告知 pickle 如何解码由 Python 2 所封存的 8 位字符串实例；这两个参数的默认值分别为 'ASCII' 和 'strict'。 <em>encoding</em> 可设为 'bytes' 以将这些 8 位字符串实例作为字节对象来读取。</p>
<dl class="method">
<dt id="pickle.Unpickler.load">
<code class="sig-name descname">load</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Unpickler.load" title="永久链接至目标">¶</a></dt>
<dd><p>从构造函数中指定的文件对象里读取打包好的对象，重建其中特定对象的层次结构并返回。打包对象以外的其他字节将被忽略。</p>
</dd></dl>

<dl class="method">
<dt id="pickle.Unpickler.persistent_load">
<code class="sig-name descname">persistent_load</code><span class="sig-paren">(</span><em class="sig-param">pid</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Unpickler.persistent_load" title="永久链接至目标">¶</a></dt>
<dd><p>默认抛出 <a class="reference internal" href="#pickle.UnpicklingError" title="pickle.UnpicklingError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UnpicklingError</span></code></a> 异常。</p>
<p>如果定义了此方法，<a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_load()</span></code></a> 应当返回持久化 ID <em>pid</em> 所指定的对象。 如果遇到无效的持久化 ID，则应当引发 <a class="reference internal" href="#pickle.UnpicklingError" title="pickle.UnpicklingError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UnpicklingError</span></code></a>。</p>
<p>参阅 <a class="reference internal" href="#pickle-persistent"><span class="std std-ref">持久化外部对象</span></a> 获取详情和使用示例。</p>
</dd></dl>

<dl class="method">
<dt id="pickle.Unpickler.find_class">
<code class="sig-name descname">find_class</code><span class="sig-paren">(</span><em class="sig-param">module</em>, <em class="sig-param">name</em><span class="sig-paren">)</span><a class="headerlink" href="#pickle.Unpickler.find_class" title="永久链接至目标">¶</a></dt>
<dd><p>如有必要，导入 <em>module</em> 模块并返回其中名叫 <em>name</em> 的对象，其中 <em>module</em> 和 <em>name</em> 参数都是 <a class="reference internal" href="stdtypes.html#str" title="str"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> 对象。注意，不要被这个函数的名字迷惑，<a class="reference internal" href="#pickle.Unpickler.find_class" title="pickle.Unpickler.find_class"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_class()</span></code></a> 同样可以用来导入函数。</p>
<p>子类可以重载此方法，来控制加载对象的类型和加载对象的方式，从而尽可能降低安全风险。参阅 <a class="reference internal" href="#pickle-restrict"><span class="std std-ref">限制全局变量</span></a> 获取更详细的信息。</p>
</dd></dl>

</dd></dl>

</div>
<div class="section" id="what-can-be-pickled-and-unpickled">
<span id="pickle-picklable"></span><h2>可以被打包/解包的对象<a class="headerlink" href="#what-can-be-pickled-and-unpickled" title="永久链接至标题">¶</a></h2>
<p>下列类型可以被打包：</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">None</span></code>、<code class="docutils literal notranslate"><span class="pre">True</span></code> 和 <code class="docutils literal notranslate"><span class="pre">False</span></code></p></li>
<li><p>整数、浮点数、复数</p></li>
<li><p>str、byte、bytearray</p></li>
<li><p>只包含可打包对象的集合，包括 tuple、list、set 和 dict</p></li>
<li><p>定义在模块顶层的函数（使用 <a class="reference internal" href="../reference/compound_stmts.html#def"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">def</span></code></a> 定义，<a class="reference internal" href="../reference/expressions.html#lambda"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">lambda</span></code></a> 函数则不可以）</p></li>
<li><p>定义在模块顶层的内置函数</p></li>
<li><p>定义在模块顶层的类</p></li>
<li><p>某些类实例，这些类的 <a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__dict__</span></code></a> 属性值或 <a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a> 函数的返回值可以被打包（详情参阅 <a class="reference internal" href="#pickle-inst"><span class="std std-ref">打包类实例</span></a> 这一段）。</p></li>
</ul>
<p>尝试打包不能被打包的对象会抛出 <a class="reference internal" href="#pickle.PicklingError" title="pickle.PicklingError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">PicklingError</span></code></a> 异常，异常发生时，可能有部分字节已经被写入指定文件中。尝试打包递归层级很深的对象时，可能会超出最大递归层级限制，此时会抛出 <a class="reference internal" href="exceptions.html#RecursionError" title="RecursionError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">RecursionError</span></code></a> 异常，可以通过 <a class="reference internal" href="sys.html#sys.setrecursionlimit" title="sys.setrecursionlimit"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.setrecursionlimit()</span></code></a> 调整递归层级，不过请谨慎使用这个函数，因为可能会导致解释器崩溃。</p>
<p>注意，函数（内建函数或用户自定义函数）在被打包时，引用的是函数全名。<a class="footnote-reference brackets" href="#id7" id="id2">2</a> 这意味着只有函数所在的模块名，与函数名会被打包，函数体及其属性不会被打包。因此，在解包的环境中，函数所属的模块必须是可以被导入的，而且模块必须包含这个函数被打包时的名称，否则会抛出异常。<a class="footnote-reference brackets" href="#id8" id="id3">3</a></p>
<p>同样的，类也只打包名称，所以在解包环境中也有和函数相同的限制。注意，类体及其数据不会被打包，所以在下面的例子中类属性 <code class="docutils literal notranslate"><span class="pre">attr</span></code> 不会存在于解包后的环境中：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Foo</span><span class="p">:</span>
    <span class="n">attr</span> <span class="o">=</span> <span class="s1">&#39;A class attribute&#39;</span>

<span class="n">picklestring</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">Foo</span><span class="p">)</span>
</pre></div>
</div>
<p>这些限制决定了为什么必须在一个模块的顶层定义可打包的函数和类。</p>
<p>类似的，在打包类的实例时，其类体和类数据不会跟着实例一起被打包，只有实例数据会被打包。这样设计是有目的的，在将来修复类中的错误、给类增加方法之后，仍然可以载入原来版本类实例的打包数据来还原该实例。如果你准备长期使用一个对象，可能会同时存在较多版本的类体，可以为对象添加版本号，这样就可以通过类的 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a> 方法将老版本转换成新版本。</p>
</div>
<div class="section" id="pickling-class-instances">
<span id="pickle-inst"></span><h2>打包类实例<a class="headerlink" href="#pickling-class-instances" title="永久链接至标题">¶</a></h2>
<p>在本节中，我们描述了可用于定义、自定义和控制如何打包和解包类实例的通用流程。</p>
<p>通常，使一个实例可被打包不需要附加任何代码。Pickle 默认会通过 Python 的内省机制获得实例的类及属性。而当实例解包时，它的 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> 方法通常 <em>不会</em> 被调用。其默认动作是：先创建一个未初始化的实例，然后还原其属性，下面的代码展示了这种行为的实现机制：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="vm">__class__</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">attributes</span><span class="p">):</span>
    <span class="n">obj</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span>
    <span class="n">obj</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">attributes</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">obj</span>
</pre></div>
</div>
<p>类可以改变默认行为，只需定义以下一种或几种特殊方法：</p>
<dl class="method">
<dt id="object.__getnewargs_ex__">
<code class="sig-prename descclassname">object.</code><code class="sig-name descname">__getnewargs_ex__</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#object.__getnewargs_ex__" title="永久链接至目标">¶</a></dt>
<dd><p>对于使用第 2 版或更高版协议的 pickle，实现了 <a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs_ex__()</span></code></a> 方法的类可以控制在解包时传给 <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> 方法的参数。本方法必须返回一对 <code class="docutils literal notranslate"><span class="pre">(args,</span> <span class="pre">kwargs)</span></code> 用于构建对象，其中 <em>args</em> 是表示位置参数的 tuple，而 <em>kwargs</em> 是表示命名参数的 dict。它们会在解包时传递给 <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> 方法。</p>
<p>如果类的 <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> 方法只接受关键字参数，则应当实现这个方法。否则，为了兼容性，更推荐实现 <a class="reference internal" href="#object.__getnewargs__" title="object.__getnewargs__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs__()</span></code></a> 方法。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.6 版更改: </span><a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs_ex__()</span></code></a> 现在可用于第 2 和第 3 版协议。</p>
</div>
</dd></dl>

<dl class="method">
<dt id="object.__getnewargs__">
<code class="sig-prename descclassname">object.</code><code class="sig-name descname">__getnewargs__</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#object.__getnewargs__" title="永久链接至目标">¶</a></dt>
<dd><p>这个方法与上一个 <a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs_ex__()</span></code></a> 方法类似，但仅支持位置参数。它要求返回一个 tuple 类型的 <code class="docutils literal notranslate"><span class="pre">args</span></code>，用于解包时传递给 <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> 方法。</p>
<p>如果定义了 <a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs_ex__()</span></code></a>，那么 <a class="reference internal" href="#object.__getnewargs__" title="object.__getnewargs__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs__()</span></code></a> 就不会被调用。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.6 版更改: </span>在 Python 3.6 前，第 2、3 版协议会调用 <a class="reference internal" href="#object.__getnewargs__" title="object.__getnewargs__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs__()</span></code></a>，更高版本协议会调用 <a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs_ex__()</span></code></a>。</p>
</div>
</dd></dl>

<dl class="method">
<dt id="object.__getstate__">
<code class="sig-prename descclassname">object.</code><code class="sig-name descname">__getstate__</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#object.__getstate__" title="永久链接至目标">¶</a></dt>
<dd><p>类还可以进一步控制其实例的打包过程。如果类定义了 <a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a>，它就会被调用，其返回的对象是被当做实例内容来打包的，否则打包的是实例的 __dict__。如果 <a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a> 未定义，实例的 <a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__dict__</span></code></a> 会被照常打包。</p>
</dd></dl>

<dl class="method">
<dt id="object.__setstate__">
<code class="sig-prename descclassname">object.</code><code class="sig-name descname">__setstate__</code><span class="sig-paren">(</span><em class="sig-param">state</em><span class="sig-paren">)</span><a class="headerlink" href="#object.__setstate__" title="永久链接至目标">¶</a></dt>
<dd><p>当解包时，如果类定义了 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a>，就会在已解包状态下调用它。此时不要求实例的 state 对象必须是 dict。没有定义此方法的话，先前打包的 state 对象必须是 dict，且该 dict 内容会在解包时赋给新实例的 __dict__。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>如果 <a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a> 返回 False，那么在解包时就不会调用 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a> 方法。</p>
</div>
</dd></dl>

<p>参考 <a class="reference internal" href="#pickle-state"><span class="std std-ref">处理有状态的对象</span></a> 一段获取如何使用 <a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a> 和 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a> 方法的更多信息。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>在解封时，实例的某些方法例如 <a class="reference internal" href="../reference/datamodel.html#object.__getattr__" title="object.__getattr__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattr__()</span></code></a>, <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a> 或 <a class="reference internal" href="../reference/datamodel.html#object.__setattr__" title="object.__setattr__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setattr__()</span></code></a> 可能会被调用。 由于这些方法可能要求某些内部不变量为真值，因此该类型应当实现 <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> 以建立这样的不变量，因为当解封一个实例时 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> 并不会被调用。</p>
</div>
<p id="index-4">可以看出，其实 pickle 并不直接调用上面的几个函数。事实上，这几个函数是复制协议的一部分，它们实现了 <a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 这一特殊接口。复制协议提供了统一的接口，用于在打包或复制对象的过程中取得所需数据。<a class="footnote-reference brackets" href="#id9" id="id4">4</a></p>
<p>尽管这个协议功能很强，但是直接在类中实现 <a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 接口容易产生错误。因此，设计类时应当尽可能的使用高级接口（比如 <a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getnewargs_ex__()</span></code></a>、<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a> 和 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a>）。后面仍然可以看到直接实现 <a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 接口的状况，可能别无他法，可能为了获得更好的性能，或者两者皆有之。</p>
<dl class="method">
<dt id="object.__reduce__">
<code class="sig-prename descclassname">object.</code><code class="sig-name descname">__reduce__</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#object.__reduce__" title="永久链接至目标">¶</a></dt>
<dd><p>该接口当前定义如下。<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 方法不带任何参数，并且应返回字符串或最好返回一个元组（返回的对象通常称为“reduce 值”）。</p>
<p>如果返回字符串，该字符串会被当做一个全局变量的名称。它应该是对象相对于其模块的本地名称，pickle 模块会搜索模块命名空间来确定对象所属的模块。这种行为常在单例模式使用。</p>
<p>当返回的是一个元组时，它的长度必须在二至五项之间。 可选项可以被省略或将值设为 <code class="docutils literal notranslate"><span class="pre">None</span></code>。 每项的语义分别如下所示：</p>
<ul class="simple">
<li><p>一个可调用对象，该对象会在创建对象的最初版本时调用。</p></li>
<li><p>可调用对象的参数，是一个元组。如果可调用对象不接受参数，必须提供一个空元组。</p></li>
<li><p>可选元素，用于表示对象的状态，将被传给前述的 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a> 方法。 如果对象没有此方法，则这个元素必须是字典类型，并会被添加至 <a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__dict__</span></code></a> 属性中。</p></li>
<li><p>可选元素，一个返回连续项的迭代器（而不是序列）。这些项会被 <code class="docutils literal notranslate"><span class="pre">obj.append(item)</span></code> 逐个加入对象，或被 <code class="docutils literal notranslate"><span class="pre">obj.extend(list_of_items)</span></code> 批量加入对象。这个元素主要用于 list 的子类，也可以用于那些正确实现了 <code class="xref py py-meth docutils literal notranslate"><span class="pre">append()</span></code> 和 <code class="xref py py-meth docutils literal notranslate"><span class="pre">extend()</span></code> 方法的类。（具体是使用 <code class="xref py py-meth docutils literal notranslate"><span class="pre">append()</span></code> 还是 <code class="xref py py-meth docutils literal notranslate"><span class="pre">extend()</span></code> 取决于 pickle 协议版本以及待插入元素的项数，所以这两个方法必须同时被类支持。）</p></li>
<li><p>可选元素，一个返回连续键值对的迭代器（而不是序列）。这些键值对将会以 <code class="docutils literal notranslate"><span class="pre">obj[key]</span> <span class="pre">=</span> <span class="pre">value</span></code> 的方式存储于对象中。该元素主要用于 dict 子类，也可以用于那些实现了 <a class="reference internal" href="../reference/datamodel.html#object.__setitem__" title="object.__setitem__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setitem__()</span></code></a> 的类。</p></li>
</ul>
</dd></dl>

<dl class="method">
<dt id="object.__reduce_ex__">
<code class="sig-prename descclassname">object.</code><code class="sig-name descname">__reduce_ex__</code><span class="sig-paren">(</span><em class="sig-param">protocol</em><span class="sig-paren">)</span><a class="headerlink" href="#object.__reduce_ex__" title="永久链接至目标">¶</a></dt>
<dd><p>作为替代选项，也可以实现 <a class="reference internal" href="#object.__reduce_ex__" title="object.__reduce_ex__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce_ex__()</span></code></a> 方法。 此方法的唯一不同之处在于它应接受一个整型参数用于指定协议版本。 如果定义了这个函数，则会覆盖 <a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 的行为。 此外，<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__reduce__()</span></code></a> 方法会自动成为扩展版方法的同义词。 这个函数主要用于为以前的 Python 版本提供向后兼容的 reduce 值。</p>
</dd></dl>

<div class="section" id="persistence-of-external-objects">
<span id="pickle-persistent"></span><h3>持久化外部对象<a class="headerlink" href="#persistence-of-external-objects" title="永久链接至标题">¶</a></h3>
<p id="index-5">为了获取对象持久化的利益， <a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块支持引用已封存数据流之外的对象。 这样的对象是通过一个持久化 ID 来引用的，它应当是一个由字母数字类字符组成的字符串 (对于第 0 版协议) <a class="footnote-reference brackets" href="#id10" id="id5">5</a> 或是一个任意对象 (用于任意新版协议)。</p>
<p><a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块不提供对持久化 ID 的解析工作，它将解析工作分配给用户定义的方法，分别是 pickler 中的 <a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_id()</span></code></a> 方法和 unpickler 中的 <a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_load()</span></code></a> 方法。</p>
<p>要通过持久化 ID 将外部对象打包，必须在 pickler 中实现 <a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_id()</span></code></a> 方法，该方法接受需要被打包的对象作为参数，返回一个 <code class="docutils literal notranslate"><span class="pre">None</span></code> 或返回该对象的持久化 ID。如果返回 <code class="docutils literal notranslate"><span class="pre">None</span></code>，该对象会被按照默认方式打包为数据流。如果返回字符串形式的持久化 ID，则会打包这个字符串和一个标记，这样 unpickler 才能将其识别为持久化 ID。</p>
<p>要解封外部对象，Unpickler 必须实现 <a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal notranslate"><span class="pre">persistent_load()</span></code></a> 方法，接受一个持久化 ID 对象作为参数并返回一个引用的对象。</p>
<p>下面是一个全面的例子，展示了如何使用持久化 ID 来封存外部对象。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Simple example presenting how persistent ID can be used to pickle</span>
<span class="c1"># external objects by reference.</span>

<span class="kn">import</span> <span class="nn">pickle</span>
<span class="kn">import</span> <span class="nn">sqlite3</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">namedtuple</span>

<span class="c1"># Simple class representing a record in our database.</span>
<span class="n">MemoRecord</span> <span class="o">=</span> <span class="n">namedtuple</span><span class="p">(</span><span class="s2">&quot;MemoRecord&quot;</span><span class="p">,</span> <span class="s2">&quot;key, task&quot;</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">DBPickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">persistent_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="c1"># Instead of pickling MemoRecord as a regular class instance, we emit a</span>
        <span class="c1"># persistent ID.</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">MemoRecord</span><span class="p">):</span>
            <span class="c1"># Here, our persistent ID is simply a tuple, containing a tag and a</span>
            <span class="c1"># key, which refers to a specific record in the database.</span>
            <span class="k">return</span> <span class="p">(</span><span class="s2">&quot;MemoRecord&quot;</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># If obj does not have a persistent ID, return None. This means obj</span>
            <span class="c1"># needs to be pickled as usual.</span>
            <span class="k">return</span> <span class="kc">None</span>


<span class="k">class</span> <span class="nc">DBUnpickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Unpickler</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">file</span><span class="p">,</span> <span class="n">connection</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="o">=</span> <span class="n">connection</span>

    <span class="k">def</span> <span class="nf">persistent_load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pid</span><span class="p">):</span>
        <span class="c1"># This method is invoked whenever a persistent ID is encountered.</span>
        <span class="c1"># Here, pid is the tuple returned by DBPickler.</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">type_tag</span><span class="p">,</span> <span class="n">key_id</span> <span class="o">=</span> <span class="n">pid</span>
        <span class="k">if</span> <span class="n">type_tag</span> <span class="o">==</span> <span class="s2">&quot;MemoRecord&quot;</span><span class="p">:</span>
            <span class="c1"># Fetch the referenced record from the database and return it.</span>
            <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT * FROM memos WHERE key=?&quot;</span><span class="p">,</span> <span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">key_id</span><span class="p">),))</span>
            <span class="n">key</span><span class="p">,</span> <span class="n">task</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">MemoRecord</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">task</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># Always raises an error if you cannot return the correct object.</span>
            <span class="c1"># Otherwise, the unpickler will think None is the object referenced</span>
            <span class="c1"># by the persistent ID.</span>
            <span class="k">raise</span> <span class="n">pickle</span><span class="o">.</span><span class="n">UnpicklingError</span><span class="p">(</span><span class="s2">&quot;unsupported persistent object&quot;</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="kn">import</span> <span class="nn">io</span>
    <span class="kn">import</span> <span class="nn">pprint</span>

    <span class="c1"># Initialize and populate our database.</span>
    <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;:memory:&quot;</span><span class="p">)</span>
    <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
    <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)&quot;</span><span class="p">)</span>
    <span class="n">tasks</span> <span class="o">=</span> <span class="p">(</span>
        <span class="s1">&#39;give food to fish&#39;</span><span class="p">,</span>
        <span class="s1">&#39;prepare group meeting&#39;</span><span class="p">,</span>
        <span class="s1">&#39;fight with a zebra&#39;</span><span class="p">,</span>
        <span class="p">)</span>
    <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">tasks</span><span class="p">:</span>
        <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;INSERT INTO memos VALUES(NULL, ?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">task</span><span class="p">,))</span>

    <span class="c1"># Fetch the records to be pickled.</span>
    <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT * FROM memos&quot;</span><span class="p">)</span>
    <span class="n">memos</span> <span class="o">=</span> <span class="p">[</span><span class="n">MemoRecord</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">task</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">cursor</span><span class="p">]</span>
    <span class="c1"># Save the records using our custom DBPickler.</span>
    <span class="n">file</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
    <span class="n">DBPickler</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">memos</span><span class="p">)</span>

    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Pickled records:&quot;</span><span class="p">)</span>
    <span class="n">pprint</span><span class="o">.</span><span class="n">pprint</span><span class="p">(</span><span class="n">memos</span><span class="p">)</span>

    <span class="c1"># Update a record, just for good measure.</span>
    <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;UPDATE memos SET task=&#39;learn italian&#39; WHERE key=1&quot;</span><span class="p">)</span>

    <span class="c1"># Load the records from the pickle data stream.</span>
    <span class="n">file</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
    <span class="n">memos</span> <span class="o">=</span> <span class="n">DBUnpickler</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">conn</span><span class="p">)</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>

    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Unpickled records:&quot;</span><span class="p">)</span>
    <span class="n">pprint</span><span class="o">.</span><span class="n">pprint</span><span class="p">(</span><span class="n">memos</span><span class="p">)</span>


<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="dispatch-tables">
<span id="pickle-dispatch"></span><h3>Dispatch 表<a class="headerlink" href="#dispatch-tables" title="永久链接至标题">¶</a></h3>
<p>如果想对某些类进行自定义封存，而又不想在类中增加用于封存的代码，就可以创建带有特殊 dispatch 表的 pickler。</p>
<p>在 <a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">copyreg</span></code></a> 模块的 <code class="xref py py-data docutils literal notranslate"><span class="pre">copyreg.dispatch_table</span></code> 中定义了全局 dispatch 表。因此，可以使用 <code class="xref py py-data docutils literal notranslate"><span class="pre">copyreg.dispatch_table</span></code> 修改后的副本作为自有 dispatch 表。</p>
<p>例如：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">f</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="n">p</span><span class="o">.</span><span class="n">dispatch_table</span> <span class="o">=</span> <span class="n">copyreg</span><span class="o">.</span><span class="n">dispatch_table</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">p</span><span class="o">.</span><span class="n">dispatch_table</span><span class="p">[</span><span class="n">SomeClass</span><span class="p">]</span> <span class="o">=</span> <span class="n">reduce_SomeClass</span>
</pre></div>
</div>
<p>创建了一个带有自有 dispatch 表的 <a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal notranslate"><span class="pre">pickle.Pickler</span></code></a> 实例，它可以对 <code class="docutils literal notranslate"><span class="pre">SomeClass</span></code> 类进行特殊处理。另外，下列代码：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyPickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">):</span>
    <span class="n">dispatch_table</span> <span class="o">=</span> <span class="n">copyreg</span><span class="o">.</span><span class="n">dispatch_table</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
    <span class="n">dispatch_table</span><span class="p">[</span><span class="n">SomeClass</span><span class="p">]</span> <span class="o">=</span> <span class="n">reduce_SomeClass</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">MyPickler</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</pre></div>
</div>
<p>完成了相同的操作，但所有 <code class="docutils literal notranslate"><span class="pre">MyPickler</span></code> 的实例都会共用同一份 dispatch 表。使用 <a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">copyreg</span></code></a> 模块实现的等效代码是：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">copyreg</span><span class="o">.</span><span class="n">pickle</span><span class="p">(</span><span class="n">SomeClass</span><span class="p">,</span> <span class="n">reduce_SomeClass</span><span class="p">)</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="handling-stateful-objects">
<span id="pickle-state"></span><h3>处理有状态的对象<a class="headerlink" href="#handling-stateful-objects" title="永久链接至标题">¶</a></h3>
<p id="index-6">下面的示例展示了如何修改类在封存时的行为。其中 <code class="xref py py-class docutils literal notranslate"><span class="pre">TextReader</span></code> 类打开了一个文本文件，每次调用其 <code class="xref py py-meth docutils literal notranslate"><span class="pre">readline()</span></code> 方法则返回行号和该行的字符。 在封存这个 <code class="xref py py-class docutils literal notranslate"><span class="pre">TextReader</span></code> 的实例时，<em>除了</em> 文件对象，其他属性都会被保存。 当解封实例时，需要重新打开文件，然后从上次的位置开始继续读取。实现这些功能需要实现 <a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setstate__()</span></code></a> 和 <a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getstate__()</span></code></a> 方法。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">TextReader</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;Print and number lines in a text file.&quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">lineno</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="nf">readline</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">lineno</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="n">line</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">file</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">line</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>
        <span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">):</span>
            <span class="n">line</span> <span class="o">=</span> <span class="n">line</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="k">return</span> <span class="s2">&quot;</span><span class="si">%i</span><span class="s2">: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lineno</span><span class="p">,</span> <span class="n">line</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__getstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c1"># Copy the object&#39;s state from self.__dict__ which contains</span>
        <span class="c1"># all our instance attributes. Always use the dict.copy()</span>
        <span class="c1"># method to avoid modifying the original state.</span>
        <span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
        <span class="c1"># Remove the unpicklable entries.</span>
        <span class="k">del</span> <span class="n">state</span><span class="p">[</span><span class="s1">&#39;file&#39;</span><span class="p">]</span>
        <span class="k">return</span> <span class="n">state</span>

    <span class="k">def</span> <span class="nf">__setstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
        <span class="c1"># Restore instance attributes (i.e., filename and lineno).</span>
        <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
        <span class="c1"># Restore the previously opened file&#39;s state. To do so, we need to</span>
        <span class="c1"># reopen it and read from it until the line count is restored.</span>
        <span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lineno</span><span class="p">):</span>
            <span class="n">file</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
        <span class="c1"># Finally, save the file.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">file</span> <span class="o">=</span> <span class="n">file</span>
</pre></div>
</div>
<p>使用方法如下所示：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">reader</span> <span class="o">=</span> <span class="n">TextReader</span><span class="p">(</span><span class="s2">&quot;hello.txt&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">reader</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="go">&#39;1: Hello world!&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">reader</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="go">&#39;2: I am line number two.&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">new_reader</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">new_reader</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="go">&#39;3: Goodbye!&#39;</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="restricting-globals">
<span id="pickle-restrict"></span><h2>限制全局变量<a class="headerlink" href="#restricting-globals" title="永久链接至标题">¶</a></h2>
<p id="index-7">默认情况下，解封将会导入在 pickle 数据中找到的任何类或函数。 对于许多应用来说，此行为是不可接受的，因为它会允许解封器导入并发起调用任意代码。 只须考虑当这个手工构建的 pickle 数据流被加载时会做什么:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">pickle</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">pickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="sa">b</span><span class="s2">&quot;cos</span><span class="se">\n</span><span class="s2">system</span><span class="se">\n</span><span class="s2">(S&#39;echo hello world&#39;</span><span class="se">\n</span><span class="s2">tR.&quot;</span><span class="p">)</span>
<span class="go">hello world</span>
<span class="go">0</span>
</pre></div>
</div>
<p>在这个例子里，解封器导入 <a class="reference internal" href="os.html#os.system" title="os.system"><code class="xref py py-func docutils literal notranslate"><span class="pre">os.system()</span></code></a> 函数然后应用字符串参数 &quot;echo hello world&quot;。 虽然这个例子不具攻击性，但是不难想象别人能够通过此方式对你的系统造成损害。</p>
<p>出于这样的理由，你可能会希望通过定制 <a class="reference internal" href="#pickle.Unpickler.find_class" title="pickle.Unpickler.find_class"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Unpickler.find_class()</span></code></a> 来控制要解封的对象。 与其名称所提示的不同，<a class="reference internal" href="#pickle.Unpickler.find_class" title="pickle.Unpickler.find_class"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Unpickler.find_class()</span></code></a> 会在执行对任何全局对象（例如一个类或一个函数）的请求时被调用。 因此可以完全禁止全局对象或是将它们限制在一个安全的子集中。</p>
<p>下面的例子是一个解封器，它只允许某一些安全的来自 <a class="reference internal" href="builtins.html#module-builtins" title="builtins: The module that provides the built-in namespace."><code class="xref py py-mod docutils literal notranslate"><span class="pre">builtins</span></code></a> 模块的类被加载:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">builtins</span>
<span class="kn">import</span> <span class="nn">io</span>
<span class="kn">import</span> <span class="nn">pickle</span>

<span class="n">safe_builtins</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s1">&#39;range&#39;</span><span class="p">,</span>
    <span class="s1">&#39;complex&#39;</span><span class="p">,</span>
    <span class="s1">&#39;set&#39;</span><span class="p">,</span>
    <span class="s1">&#39;frozenset&#39;</span><span class="p">,</span>
    <span class="s1">&#39;slice&#39;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">class</span> <span class="nc">RestrictedUnpickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Unpickler</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">find_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">module</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="c1"># Only allow safe classes from builtins.</span>
        <span class="k">if</span> <span class="n">module</span> <span class="o">==</span> <span class="s2">&quot;builtins&quot;</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">safe_builtins</span><span class="p">:</span>
            <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">builtins</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
        <span class="c1"># Forbid everything else.</span>
        <span class="k">raise</span> <span class="n">pickle</span><span class="o">.</span><span class="n">UnpicklingError</span><span class="p">(</span><span class="s2">&quot;global &#39;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">&#39; is forbidden&quot;</span> <span class="o">%</span>
                                     <span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">name</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">restricted_loads</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Helper function analogous to pickle.loads().&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">RestrictedUnpickler</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">s</span><span class="p">))</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
</pre></div>
</div>
<p>我们这个解封器的一个示例用法所达成的目标:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">restricted_loads</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mi">15</span><span class="p">)]))</span>
<span class="go">[1, 2, range(0, 15)]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">restricted_loads</span><span class="p">(</span><span class="sa">b</span><span class="s2">&quot;cos</span><span class="se">\n</span><span class="s2">system</span><span class="se">\n</span><span class="s2">(S&#39;echo hello world&#39;</span><span class="se">\n</span><span class="s2">tR.&quot;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
  <span class="c">...</span>
<span class="gr">pickle.UnpicklingError</span>: <span class="n">global &#39;os.system&#39; is forbidden</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">restricted_loads</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;cbuiltins</span><span class="se">\n</span><span class="s1">eval</span><span class="se">\n</span><span class="s1">&#39;</span>
<span class="gp">... </span>                 <span class="sa">b</span><span class="s1">&#39;(S</span><span class="se">\&#39;</span><span class="s1">getattr(__import__(&quot;os&quot;), &quot;system&quot;)&#39;</span>
<span class="gp">... </span>                 <span class="sa">b</span><span class="s1">&#39;(&quot;echo hello world&quot;)</span><span class="se">\&#39;\n</span><span class="s1">tR.&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
  <span class="c">...</span>
<span class="gr">pickle.UnpicklingError</span>: <span class="n">global &#39;builtins.eval&#39; is forbidden</span>
</pre></div>
</div>
<p>正如我们这个例子所显示的，对于允许解封的对象你必须要保持谨慎。 因此如果要保证安全，你可以考虑其他选择例如 <a class="reference internal" href="xmlrpc.client.html#module-xmlrpc.client" title="xmlrpc.client: XML-RPC client access."><code class="xref py py-mod docutils literal notranslate"><span class="pre">xmlrpc.client</span></code></a> 中的编组 API 或是第三方解决方案。</p>
</div>
<div class="section" id="performance">
<h2>性能<a class="headerlink" href="#performance" title="永久链接至标题">¶</a></h2>
<p>较新版本的 pickle 协议（第 2 版或更高）具有针对某些常见特性和内置类型的高效二进制编码格式。 此外，<a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块还拥有一个以 C 编写的透明优化器。</p>
</div>
<div class="section" id="examples">
<span id="pickle-example"></span><h2>例子<a class="headerlink" href="#examples" title="永久链接至标题">¶</a></h2>
<p>对于最简单的代码，请使用 <a class="reference internal" href="#pickle.dump" title="pickle.dump"><code class="xref py py-func docutils literal notranslate"><span class="pre">dump()</span></code></a> 和 <a class="reference internal" href="#pickle.load" title="pickle.load"><code class="xref py py-func docutils literal notranslate"><span class="pre">load()</span></code></a> 函数。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pickle</span>

<span class="c1"># An arbitrary collection of objects supported by pickle.</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="o">+</span><span class="mi">6</span><span class="n">j</span><span class="p">],</span>
    <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;character string&quot;</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&quot;byte string&quot;</span><span class="p">),</span>
    <span class="s1">&#39;c&#39;</span><span class="p">:</span> <span class="p">{</span><span class="kc">None</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">}</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;data.pickle&#39;</span><span class="p">,</span> <span class="s1">&#39;wb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="c1"># Pickle the &#39;data&#39; dictionary using the highest protocol available.</span>
    <span class="n">pickle</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">pickle</span><span class="o">.</span><span class="n">HIGHEST_PROTOCOL</span><span class="p">)</span>
</pre></div>
</div>
<p>以下示例读取之前封存的数据。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pickle</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;data.pickle&#39;</span><span class="p">,</span> <span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="c1"># The protocol version used is detected automatically, so we do not</span>
    <span class="c1"># have to specify it.</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<dl class="simple">
<dt>模块 <a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">copyreg</span></code></a></dt><dd><p>为扩展类型提供 pickle 接口所需的构造函数。</p>
</dd>
<dt>模块 <a class="reference internal" href="pickletools.html#module-pickletools" title="pickletools: Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickletools</span></code></a></dt><dd><p>用于处理和分析已打包数据的工具。</p>
</dd>
<dt>模块 <a class="reference internal" href="shelve.html#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal notranslate"><span class="pre">shelve</span></code></a></dt><dd><p>带索引的数据库，用于存放对象，使用了 <a class="reference internal" href="#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块。</p>
</dd>
<dt>模块 <a class="reference internal" href="copy.html#module-copy" title="copy: Shallow and deep copy operations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">copy</span></code></a></dt><dd><p>浅层 (shallow) 和深层 (deep) 复制对象操作</p>
</dd>
<dt>模块 <a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a></dt><dd><p>高效地序列化内置类型的数据。</p>
</dd>
</dl>
</div>
<p class="rubric">备注</p>
<dl class="footnote brackets">
<dt class="label" id="id6"><span class="brackets"><a class="fn-backref" href="#id1">1</a></span></dt>
<dd><p>不要把它与 <a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">marshal</span></code></a> 模块混淆。</p>
</dd>
<dt class="label" id="id7"><span class="brackets"><a class="fn-backref" href="#id2">2</a></span></dt>
<dd><p>这就是为什么 <a class="reference internal" href="../reference/expressions.html#lambda"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">lambda</span></code></a> 函数不可以被打包：所有的匿名函数都有同一个名字：<code class="docutils literal notranslate"><span class="pre">&lt;lambda&gt;</span></code>。</p>
</dd>
<dt class="label" id="id8"><span class="brackets"><a class="fn-backref" href="#id3">3</a></span></dt>
<dd><p>抛出的异常有可能是 <a class="reference internal" href="exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportError</span></code></a> 或 <a class="reference internal" href="exceptions.html#AttributeError" title="AttributeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">AttributeError</span></code></a>，也可能是其他异常。</p>
</dd>
<dt class="label" id="id9"><span class="brackets"><a class="fn-backref" href="#id4">4</a></span></dt>
<dd><p><a class="reference internal" href="copy.html#module-copy" title="copy: Shallow and deep copy operations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">copy</span></code></a> 模块使用这一协议实现浅层 (shallow) 和深层 (deep) 复制操作。</p>
</dd>
<dt class="label" id="id10"><span class="brackets"><a class="fn-backref" href="#id5">5</a></span></dt>
<dd><p>对字母数字类字符的限制是由于持久化 ID 在协议版本 0 中是由分行符来分隔的。 因此如果持久化 ID 中出现任何形式的分行符，封存结果就将变得无法读取。</p>
</dd>
</dl>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">目录</a></h3>
  <ul>
<li><a class="reference internal" href="#"><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code> —— Python 对象序列化</a><ul>
<li><a class="reference internal" href="#relationship-to-other-python-modules">与其他 Python 模块间的关系</a><ul>
<li><a class="reference internal" href="#comparison-with-marshal">与 <code class="docutils literal notranslate"><span class="pre">marshal</span></code> 间的关系</a></li>
<li><a class="reference internal" href="#comparison-with-json">与 <code class="docutils literal notranslate"><span class="pre">json</span></code> 模块的比较</a></li>
</ul>
</li>
<li><a class="reference internal" href="#data-stream-format">数据流格式</a></li>
<li><a class="reference internal" href="#module-interface">模块接口</a></li>
<li><a class="reference internal" href="#what-can-be-pickled-and-unpickled">可以被打包/解包的对象</a></li>
<li><a class="reference internal" href="#pickling-class-instances">打包类实例</a><ul>
<li><a class="reference internal" href="#persistence-of-external-objects">持久化外部对象</a></li>
<li><a class="reference internal" href="#dispatch-tables">Dispatch 表</a></li>
<li><a class="reference internal" href="#handling-stateful-objects">处理有状态的对象</a></li>
</ul>
</li>
<li><a class="reference internal" href="#restricting-globals">限制全局变量</a></li>
<li><a class="reference internal" href="#performance">性能</a></li>
<li><a class="reference internal" href="#examples">例子</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="persistence.html"
                        title="上一章">数据持久化</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="copyreg.html"
                        title="下一章"><code class="xref py py-mod docutils literal notranslate"><span class="pre">copyreg</span></code> --- 注意 <code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code> 支持函数</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../bugs.html">提交 Bug</a></li>
      <li>
        <a href="https://github.com/python/cpython/blob/3.7/Doc/library/pickle.rst"
            rel="nofollow">显示源代码
        </a>
      </li>
    </ul>
  </div>
        </div>
      </div>
      <div class="clearer"></div>
    </div>  
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>导航</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="总目录"
             >索引</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python 模块索引"
             >模块</a> |</li>
        <li class="right" >
          <a href="copyreg.html" title="copyreg --- 注意 pickle 支持函数"
             >下一页</a> |</li>
        <li class="right" >
          <a href="persistence.html" title="数据持久化"
             >上一页</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="https://www.python.org/">Python</a> &#187;</li>
        <li>
          <a href="../index.html">3.7.8 Documentation</a> &#187;
        </li>

          <li class="nav-item nav-item-1"><a href="index.html" >Python 标准库</a> &#187;</li>
          <li class="nav-item nav-item-2"><a href="persistence.html" >数据持久化</a> &#187;</li>
    <li class="right">
        

    <div class="inline-search" style="display: none" role="search">
        <form class="inline-search" action="../search.html" method="get">
          <input placeholder="快速搜索" type="text" name="q" />
          <input type="submit" value="转向" />
          <input type="hidden" name="check_keywords" value="yes" />
          <input type="hidden" name="area" value="default" />
        </form>
    </div>
    <script type="text/javascript">$('.inline-search').show(0);</script>
         |
    </li>

      </ul>
    </div>  
    <div class="footer">
    &copy; <a href="../copyright.html">版权所有</a> 2001-2020, Python Software Foundation.
    <br />
    Python 软件基金会是一个非盈利组织。
    <a href="https://www.python.org/psf/donations/">请捐助。</a>
    <br />
    最后更新于 6月 29, 2020.
    <a href="../bugs.html">发现了问题</a>？
    <br />
    使用<a href="http://sphinx.pocoo.org/">Sphinx</a>2.3.1 创建。
    </div>

  </body>
</html>